﻿#region Copyright(C) 2010-2012 FI Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2018 FI Ltd. All rights reserved.
//
// SYSTEM NAME	    : FI.Net Application Framework
// COMPONENT ID	    : FI.Core.StringResource.StringRecordSet
// COMPONENT DESC   : 
//
// CREATED DATE/BY  : 18 Aug 2018 / Tian Mi
//
// REVISION HISTORY : 
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using FI.Core.Utilities;

namespace FI.Core.StringResource
{
    /// <summary>
    /// String Record Set
    /// <example>
    /// Following is the common scenerio of using StringRecordSet :
    /// - Add new string record to resource set:
    /// <code>
    ///     var stringRecordSet = new StringRecordSet();
    ///     var stringRecord = new StringRecord("CODE_TABLE", "en-US", "AuthorName", "Author Name");
    ///     stringRecordSet.Add(stringRecord);
    /// </code>
    /// - Update string record
    /// <code>
    ///     stringRecord.Value = "New Author Name";
    /// </code>
    ///     or
    /// <code>
    ///     stringRecordSet[0].Value = "New Author Name";
    /// </code>
    /// - Delete string record
    /// <code>
    ///     stringRecord.Delete();
    /// </code>
    ///     or
    /// <code>
    ///     stringRecordSet.Remove(stringRecord);
    /// </code>
    /// </example>
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix"), CollectionDataContract(IsReference = true, Namespace = Constants.Namespace)]
    public class StringRecordSet : IEnumerable<StringRecord>
    {
        [DataMember]
        private readonly List<StringRecord> stringRecordList = new List<StringRecord>();

        /// <summary>
        /// Gets the enumerator.
        /// </summary>
        /// <returns>IEnumerator for <see cref="FI.Core.StringResource.StringRecord"/></returns>
        public IEnumerator<StringRecord> GetEnumerator()
        {
            return stringRecordList.GetEnumerator();
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// <summary>
        /// Adds the specified string record.
        /// </summary>
        /// <param name="stringRecord">The string record.</param>
        public void Add(StringRecord stringRecord)
        {
            Guard.ArgumentNotNull(stringRecord, "stringRecord");
            stringRecordList.Add(stringRecord);
            stringRecord.StringRecordSet = this;
            stringRecord.MarkStringRecordAdded();
        }

        /// <summary>
        /// Removes the specified string record.
        /// </summary>
        /// <param name="stringRecord">The string record.</param>
        public void Remove(StringRecord stringRecord)
        {
            Guard.ArgumentNotNull(stringRecord, "stringRecord");
            if (stringRecord.RecordState == RecordState.Added)
            {
                stringRecordList.Remove(stringRecord);
            }
            stringRecord.MarkStringRecordRemoved();
        }

        /// <summary>
        /// Accepts the changes.
        /// </summary>
        public void AcceptChanges()
        {
            PolicyAction(stringRecord => stringRecord.AcceptChanges());
        }

        /// <summary>
        /// Rejects the changes.
        /// </summary>
        public void RejectChanges()
        {
            PolicyAction(stringRecord => stringRecord.RejectChanges());
        }

        /// <summary>
        /// Rolls the back.
        /// </summary>
        public void Rollback()
        {
            PolicyAction(stringRecord => stringRecord.Rollback());
        }

        /// <summary>
        /// Policies the action.
        /// </summary>
        /// <param name="stringRecordAction">The string record action.</param>
        private void PolicyAction(Action<StringRecord> stringRecordAction)
        {
            List<StringRecord> stringRecordsToRemove = new List<StringRecord>();
            foreach (var stringRecord in stringRecordList)
            {
                stringRecordAction(stringRecord);

                if (stringRecord.RecordState == RecordState.Deleted || stringRecord.RecordState == RecordState.Detached)
                {
                    stringRecordsToRemove.Add(stringRecord);
                }
            }

            foreach (var stringRecord in stringRecordsToRemove)
            {
                stringRecordList.Remove(stringRecord);
                stringRecord.StringRecordSet = null;
            }
        }

        /// <summary>
        /// Gets the count.
        /// </summary>
        public Int32 Count
        {
            get { return stringRecordList.Count; }
        }

        /// <summary>
        /// Gets the <see cref="FI.Core.StringResource.StringRecord"/> at the specified index.
        /// </summary>
        public StringRecord this[Int32 index]
        {
            get { return stringRecordList[index]; }
        }

        /// <summary>
        /// Gets the changes.
        /// </summary>
        /// <param name="recordState">State of the record.</param>
        /// <returns>IEnumerator for <see cref="FI.Core.StringResource.StringRecord"/></returns>
        public IEnumerable<StringRecord> GetChanges(RecordState recordState)
        {
            return (from item in stringRecordList
                    where item.RecordState == recordState
                    select item);
        }
    }
}
